﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace UIWindows.Tools.Helper
{
    public static class ICMPHelper
    {
        private static Socket _socket;
        private static byte[] _icmpByte = new byte[] { 8, 0, 0x25, 0x5a, 0x2d, 0, 0, 0, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23 };
        private static Stopwatch _stopwatch = new Stopwatch();

        static ICMPHelper()
        {
            _socket = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.Icmp);
            _socket.ReceiveTimeout = 1000;
            _socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, 1000);
        }

        public static (long Time, ICMPType Result) PING(string ip)
        {
            _stopwatch.Restart();
            _socket.SendTo(_icmpByte, 32, SocketFlags.None, new IPEndPoint(IPAddress.Parse(ip), 0));
            byte[] bytes = new byte[1024];
            EndPoint myip = new IPEndPoint(0, 0);
            ICMPType type = ICMPType.错误信息;
            try
            {
                int length = _socket.ReceiveFrom(bytes, ref myip);
                _stopwatch.Stop();
                switch ($"{bytes[20]}-{bytes[21]}")
                {
                    case "0-0": type = ICMPType.回显应答; break;
                    case "8-0": type = ICMPType.回显请求; break;
                    case "3-0": type = ICMPType.网络不可达; break;
                    case "3-1": type = ICMPType.主机不可达; break;
                    case "3-2": type = ICMPType.协议不可达; break;
                    case "3-3": type = ICMPType.端口不可达; break;
                    case "3-4": type = ICMPType.需要进行分片但设置不分比特; break;
                    case "3-5": type = ICMPType.源站选路失败; break;
                    case "3-6": type = ICMPType.目的网络未知; break;
                    case "3-7": type = ICMPType.目的主机未知; break;
                    case "3-8": type = ICMPType.源主机被隔离; break;
                    case "3-9": type = ICMPType.目的网络被强制禁止; break;
                    case "3-10": type = ICMPType.目的主机被强制禁止; break;
                    case "3-11": type = ICMPType.由于服务类型TOS_网络不可达; break;
                    case "3-12": type = ICMPType.由于服务类型TOS_主机不可达; break;
                    case "3-13": type = ICMPType.由于过滤_通信被强制禁止; break;
                    case "3-14": type = ICMPType.主机越权; break;
                    case "3-15": type = ICMPType.优先中止生效; break;
                    case "4-0": type = ICMPType.源端被关闭; break;
                    case "5-0": type = ICMPType.对网络重定向; break;
                    case "5-1": type = ICMPType.对主机重定向; break;
                    case "5-2": type = ICMPType.对服务类型和网络重定向; break;
                    case "5-3": type = ICMPType.对服务类型和主机重定向; break;
                    case "9-0": type = ICMPType.路由器通告; break;
                    case "10-0": type = ICMPType.路由器请求; break;
                    case "11-0": type = ICMPType.传输期间生存时间为0; break;
                    case "11-1": type = ICMPType.在数据报组装期间生存时间为0; break;
                    case "12-0": type = ICMPType.坏的IP首部; break;
                    case "12-1": type = ICMPType.缺少必要的选项; break;
                }
            }
            catch (Exception) { type = ICMPType.访问超时; }
            _stopwatch.Stop();
            return new(_stopwatch.ElapsedMilliseconds, type);
        }

    }
    public enum ICMPType : byte
    {
        //Type-Code
        /// <summary>
        /// 0-0
        /// </summary>
        回显应答,
        /// <summary>
        /// 8-0
        /// </summary>
        回显请求,
        /// <summary>
        /// 3-0
        /// </summary>
        网络不可达,
        /// <summary>
        /// 3-1
        /// </summary>
        主机不可达,
        /// <summary>
        /// 3-2
        /// </summary>
        协议不可达,
        /// <summary>
        /// 3-3
        /// </summary>
        端口不可达,
        /// <summary>
        /// 3-4
        /// </summary>
        需要进行分片但设置不分比特,
        /// <summary>
        /// 3-5
        /// </summary>
        源站选路失败,
        /// <summary>
        /// 3-6
        /// </summary>
        目的网络未知,
        /// <summary>
        /// 3-7
        /// </summary>
        目的主机未知,
        /// <summary>
        /// 3-8
        /// </summary>
        源主机被隔离,
        /// <summary>
        /// 3-9
        /// </summary>
        目的网络被强制禁止,
        /// <summary>
        /// 3-10
        /// </summary>
        目的主机被强制禁止,
        /// <summary>
        /// 3-11
        /// </summary>
        由于服务类型TOS_网络不可达,
        /// <summary>
        /// 3-12
        /// </summary>
        由于服务类型TOS_主机不可达,
        /// <summary>
        /// 3-13
        /// </summary>
        由于过滤_通信被强制禁止,
        /// <summary>
        /// 3-14
        /// </summary>
        主机越权,
        /// <summary>
        /// 3-15
        /// </summary>
        优先中止生效,
        /// <summary>
        /// 4-0
        /// </summary>
        源端被关闭,
        /// <summary>
        /// 5-0
        /// </summary>
        对网络重定向,
        /// <summary>
        /// 5-1
        /// </summary>
        对主机重定向,
        /// <summary>
        /// 5-2
        /// </summary>
        对服务类型和网络重定向,
        /// <summary>
        /// 5-3
        /// </summary>
        对服务类型和主机重定向,
        /// <summary>
        /// 9-0
        /// </summary>
        路由器通告,
        /// <summary>
        /// 10-0
        /// </summary>
        路由器请求,
        /// <summary>
        /// 11-0
        /// </summary>
        传输期间生存时间为0,
        /// <summary>
        /// 11-1
        /// </summary>
        在数据报组装期间生存时间为0,
        /// <summary>
        /// 12-0
        /// </summary>
        坏的IP首部,
        /// <summary>
        /// 12-1
        /// </summary>
        缺少必要的选项,



        访问超时,
        错误信息,
    }
}
